package com.yaoayao.mall.activity.consumer;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.rabbitmq.client.Channel;
import com.yaoayao.mall.activity.mapper.SeckillGoodsMapper;
import com.yaoayao.mall.activity.redis.CacheHelper;
import com.yaoayao.mall.activity.utils.DateUtil;
import com.yaoayao.mall.common.constant.RedisConst;
import com.yaoayao.mall.model.activity.SeckillGoods;
import com.yaoayao.mall.model.activity.UserRecode;
import com.yaoayao.mall.rabbit.constant.MqConst;
import org.springframework.amqp.core.ExchangeTypes;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.Exchange;
import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.QueueBinding;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.Date;
import java.util.List;

@Component
public class ActivityConsumer {

    @Autowired
    private RedisTemplate redisTemplate;

    @Resource
    private SeckillGoodsMapper seckillGoodsMapper;

    @RabbitListener(bindings = @QueueBinding(
            value = @Queue(value = MqConst.QUEUE_TASK_1,durable = "true",autoDelete = "false"),
            exchange = @Exchange(value = MqConst.EXCHANGE_DIRECT_TASK),
            key = MqConst.ROUTING_TASK_1
    ))
    public void seckillImportRedis(Message message, Channel channel){
        try {
            //半夜接收消息 将秒杀的数据导入缓存 当天
            //4.seckillGoodsMapper.selectList() 查询
            QueryWrapper<SeckillGoods> seckillGoodsQueryWrapper = new QueryWrapper<>();
            //1.审核通过
            seckillGoodsQueryWrapper.eq("status",1);
            //2.当天的商品
            seckillGoodsQueryWrapper.eq("DATE_FORMAT(start_time,'%Y-%m-%d')",
                    DateUtil.formatDate(new Date()));
            //3.必须有剩余库存
            seckillGoodsQueryWrapper.gt("stock_count",0);
            List<SeckillGoods> seckillGoodsList = seckillGoodsMapper.selectList(seckillGoodsQueryWrapper);
            if (!CollectionUtils.isEmpty(seckillGoodsList)){
                //不为空 秒杀商品存
                seckillGoodsList.forEach(seckillGoods -> {
                    //5.将结果集放入缓存中（考虑使用redis五大数据类型中哪个类型）
                    //hash h hk hv
                    //5.1先判断reids中缓存是否已经存在
                    if (!redisTemplate.opsForHash().hasKey(RedisConst.SECKILL_GOODS,
                            seckillGoods.getSkuId().toString())){
                        //不存在
                        //作为新的秒杀商品存入缓存中
                        redisTemplate.opsForHash().put(RedisConst.SECKILL_GOODS,
                                seckillGoods.getSkuId().toString(),
                                seckillGoods);
                        //6.防止超卖 秒杀商品放到货架
                        //k:List 超市名称:苹果 = new ArrayList
                        //k.add(苹果)
                        //超市名称:苹果.get（苹果）
                        // K : List 超市名称:梨 = new ArrayList
                        // k.add(梨)
                        redisTemplate.opsForList().leftPushAll(RedisConst.SECKILL_STOCK_PREFIX+seckillGoods.getSkuId(),
                                buildSkuIds(seckillGoods.getSkuId(),seckillGoods.getStockCount()));
                        //7.状态位 每一款商品都要有状态位
                        //参数1：信道
                        //参数2：消息   skuId:0  skuId:1   1有货状态
                        redisTemplate.convertAndSend("seckillpush",
                                seckillGoods.getSkuId() + ":1");
                    }
                });
            }
            channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private String[] buildSkuIds(Long skuId, Integer stockCount) {
        String[] ids = new String[stockCount];
        for (Integer i = 0; i < stockCount; i++) {
            ids[i]=skuId.toString();
        }
        return ids;
    }

    @RabbitListener(bindings = @QueueBinding(
            value = @Queue(value = MqConst.QUEUE_SECKILL_USER,durable = "true",autoDelete = "false"),
            exchange = @Exchange(value = MqConst.EXCHANGE_DIRECT_SECKILL_USER),
            key = MqConst.ROUTING_SECKILL_USER
    ))
    public void secKill(UserRecode userRecode, Message message, Channel channel) {
        try {
            //1.校验状态位
            Object status = CacheHelper.get(userRecode.getSkuId().toString());
            if (!"1".equals(status)) {
                return;
            }
            //2.用户是否来过
            Boolean flag = redisTemplate.opsForValue().setIfAbsent(
                    RedisConst.SECKILL_USER + userRecode.getUserId(),
                    "1");
            if (!flag){
                //来过了
                return;
            }

            //3.redis leftpop
            String skuId = (String)redisTemplate.opsForList().rightPop(
                    RedisConst.SECKILL_STOCK_PREFIX + userRecode.getUserId());
            if (skuId==null){
                //4.没有修改状态位
                redisTemplate.convertAndSend("seckillpush",
                        userRecode.getSkuId() + ":0");
                return;
            }
            //5.不为空 有资格保存在redis中
            redisTemplate.opsForValue().set(
                    RedisConst.SECKILL_ORDERS+userRecode.getUserId(),
                    userRecode.getSkuId());
            //收尾 更新库存
            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    /**
     * 秒杀结束清空缓存
     *
     * @param message
     * @param channel
     * @throws IOException
     */
    @RabbitListener(bindings = @QueueBinding(
            value = @Queue(value = MqConst.QUEUE_TASK_18, durable = "true", autoDelete = "false"),
            exchange = @Exchange(value = MqConst.EXCHANGE_DIRECT_TASK, type = ExchangeTypes.DIRECT, durable = "true"),
            key = {MqConst.ROUTING_TASK_18}
    ))
    public void clearRedis(String userId, Message message, Channel channel) throws IOException {

        //活动结束清空缓存
        QueryWrapper<SeckillGoods> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("status", 1);
        queryWrapper.le("end_time", new Date());
        List<SeckillGoods> list = seckillGoodsMapper.selectList(queryWrapper);
        //清空缓存
        for (SeckillGoods seckillGoods : list) {
            redisTemplate.delete(RedisConst.SECKILL_STOCK_PREFIX + seckillGoods.getSkuId());
        }
        redisTemplate.delete(RedisConst.SECKILL_GOODS);
        redisTemplate.delete(RedisConst.SECKILL_ORDERS + userId);
        redisTemplate.delete(RedisConst.SECKILL_ORDERS_USERS + userId);
        //将状态更新为结束
        SeckillGoods seckillGoodsUp = new SeckillGoods();
        seckillGoodsUp.setStatus("2");
        seckillGoodsMapper.update(seckillGoodsUp, queryWrapper);
        // 手动确认
        channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
    }
}
